//
// Created by LiuYou on 2020/8/10.
//

#ifndef CHAPTER02_SINGLELINKLIST_H
#define CHAPTER02_SINGLELINKLIST_H


#include <ostream>
#include "Object.h"

namespace ly {
    struct SingleLinkList : public Object {
        struct Node : public Object {
            int data{0};
            Node* next{nullptr};

            ~Node() override = default;

            explicit Node(int data = 0, Node* next = nullptr) : data(data), next(next) {}

            std::string toString() const override {
                return Object::toString() +
                       "Node{data=" + std::to_string(data) +
                       "}";
            }

            friend std::ostream& operator<<(std::ostream& os, const Node& node) {
                os << "data: " << node.data << " next: " << node.next;
                return os;
            }

            int getData() const {
                return data;
            }

            void setData(int data) {
                Node::data = data;
            }

            Node* getNext() const {
                return next;
            }

            void setNext(Node* next) {
                Node::next = next;
            }
        };

        using SingleLinkListNode = Node;
    private:

        SingleLinkListNode* ptrOpNode{nullptr};
        int length{0};
    public:
        std::string toString() const override {
            return Object::toString() +
                   "SingleLinkList{ptrOpNode=" + ptrOpNode->toString() +
                   ", length=" + std::to_string(length) +
                   "}";
        }

        friend std::ostream& operator<<(std::ostream& os, const SingleLinkList& list) {
            os << static_cast<const Object&>(list) << " ptrOpNode: " << list.ptrOpNode << " length: " << list.length;
            return os;
        }

        SingleLinkListNode* getPtrOpNode() const {
            return ptrOpNode;
        }

        void setPtrOpNode(SingleLinkListNode* ptrOpNode) {
            SingleLinkList::ptrOpNode = ptrOpNode;
        }

        int getLength() const {
            return length;
        }

        void setLength(int length) {
            SingleLinkList::length = length;
        }

        ~SingleLinkList() override {
            auto temp{ptrOpNode};
            while (ptrOpNode != nullptr) {
                ptrOpNode = ptrOpNode->getNext();
                delete temp;
                temp = ptrOpNode;
            }
        }

        SingleLinkList(const int* const ptrIntegerArray, int length) : length(length) {
            ptrOpNode = new SingleLinkListNode();
            auto ed{ptrOpNode};
            for (int i = 0; i < length; ++i) {
                auto temp{new SingleLinkListNode(ptrIntegerArray[i])};
                ed->setNext(temp);
                ed = temp;
            }
            ed->setNext(nullptr);
        }

        explicit SingleLinkList(SingleLinkListNode* ptrOpNode = nullptr, int length = 0) : ptrOpNode(ptrOpNode),
                                                                                           length(length) {
            this->ptrOpNode = new SingleLinkListNode();
            this->ptrOpNode->setNext(ptrOpNode);
        }
    };
}


#endif //CHAPTER02_SINGLELINKLIST_H
